
#include "../GlobalClass.h"

#include "Platform.h"

#include <QDir>
#include <QDebug>



QString _Platform::compileType()
{
#ifdef QT_NO_DEBUG
        return "release";
#else
        return "debug";
#endif
}

QString _Platform::applicationDirPath()
{
    return QCoreApplication::applicationDirPath();
}

QString _Platform::separator()
{
    return QDir::separator();
}

QString _Platform::writableLocation(QStandardPaths::StandardLocation location)
{
    return QStandardPaths::writableLocation(location);
}

void _Platform::debug()
{
    qDebug() << "Platform_Debug[QStandardPaths]:"
             << QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)
             << QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)
             << QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)
             << QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
             << QStandardPaths::writableLocation(QStandardPaths::TempLocation)
             << QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
             << QStandardPaths::writableLocation(QStandardPaths::DataLocation)
             << QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
             << QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)
             << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
             << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)
                ;
    qDebug() << "Platform_Debug[QDir]:"
             << QDir::currentPath()
             << QDir::homePath()
             << QDir::rootPath()
             << QDir::tempPath()
             << QCoreApplication::applicationDirPath()
             << QCoreApplication::libraryPaths();
}



#if defined(Q_OS_WIN32)   //win

bool _Platform::checkOne(LPCWSTR lpName)
{
    //  创建互斥量
    HANDLE m_hMutex = CreateMutex(nullptr, FALSE, lpName );
    //  检查错误代码
    if(GetLastError() == ERROR_ALREADY_EXISTS)
    {
        //  如果已有互斥量存在则释放句柄并复位互斥量
        CloseHandle(m_hMutex);
        m_hMutex = nullptr;
        return false;
    }
    else if(nullptr == m_hMutex)
    {
        qDebug() << "初始化互斥量失败";
        return false;
    }
    return true;
}






#elif defined(Q_OS_ANDROID)   //android

/*鹰：
 * getObjectField是获取对象的成员变量,getStaticObjectField是获取对象的静态成员变量
 * callMethod、callObjectMethod、callStaticMethod、callStaticObjectMethod分别是调用 成员函数,返回Object的成员函数,静态成员函数,返回Object的成员函数
   QAndroidJniObject 代表1个Java Object对象（任何类的）,其函数 .object() 返回java可识别的Java对象（jobject）
     只有String类型,需要使用其模板函数: .object<jstring>()
   QAndroidJniObject::fromString():直接返回一个Java的String对象
   Java基本类型:jint等等;String在Java中虽然为基本类型,但C++中它仍然是一个对象，签名是:Ljava/lang/String;
   调用函数时,如果要调用有参数的函数,则必须要有函数签名(sig)!（没有参数的可以不用函数签名）
     签名格式:(参数类型列表)返回类型
       括号必须有,项目之间没有逗号,返回类型为void则写V
       L 开头表示为全路径,以 ;号 结尾类
   callStaticMethod和callMethod是模板函数,其类型是返回值类型(基本类型),比如void,jint

*/

#define MAIN_ACTIVITY_PATH "cn/Leamus/MainActivity"



//检查抛出错误,在getStaticObjectField、getObjectField、callMethod、callObjectMethod、callStaticMethod、callStaticObjectMethod及类似的函数 后调用(貌似不检查,会导致卡死???没试过)
#define CHECK_EXCEPTION() \
    if(env->ExceptionCheck())\
    {\
        qDebug() << "exception occured";\
        env->ExceptionDescribe();\
        env->ExceptionClear();\
    }


/*
void showMini()
{
    QAndroidJniObject::callStaticMethod<void>(
                MAIN_ACTIVITY_PATH,
                "mini",
                "()V");
}

void moveToFront()
{
    QAndroidJniObject::callStaticMethod<void>(
                MAIN_ACTIVITY_PATH,
                "moveTaskToFrount",
                "()V");
}

void cppAssignmentJavaInt(int num)
{
    QAndroidJniObject::callStaticMethod<void>(
                "Leamus/Java/Module"
                , "setInt", "(I)V", num);
}
int cppUseJavaToInt()
{
    return QAndroidJniObject::callStaticMethod<jint>(
                "Leamus/Java/Module"
                , "getInt");
}
void cppAssignmentJavaString(QString str)
{
    QAndroidJniObject strTMP = QAndroidJniObject::fromString(str);
    QAndroidJniObject::callStaticMethod<void>(
                "Leamus/Java/Module"
                , "setString", "(Ljava/lang/String;)V"
                , strTMP.object<jstring>());
}
QString cppUseJavaToString()
{
    QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod(
                "Leamus/Java/Module"
                ,  "getString"
                ,  "()Ljava/lang/String;");
    return str.toString();
}

void keepAlive()
{

    //QAndroidJniObject::callStaticMethod<void>(
    //            "Leamus/Java/Module"
    //            ,  "keepActive");

}
*/



int _Platform::getScreenOrientation()
{
    QAndroidJniEnvironment env;
    QAndroidJniObject activity = androidActivity();

    jint orient = activity.callMethod<jint>(
                "getRequestedOrientation"
                );
    CHECK_EXCEPTION();
    return orient;

}
void _Platform::setScreenOrientation(int orient)
{
    QAndroidJniEnvironment env;
    QAndroidJniObject activity = androidActivity();

    activity.callMethod<void>(
                "setRequestedOrientation",
                "(I)V", orient);
    CHECK_EXCEPTION();

}

// 有两种方法。
// 1.
//   getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//   必须放在 Actvity 的 setContentView 调用前…… Qt 中很难操作
// 2.通过 PowerManager 来实现：
// android/os/PowerManager
//    WakeLock newWakeLock(int , String tag);
// android.os.PowerManager.WakeLock
//      void acquire();
//      void release();
//
void _Platform::keepScreenWake(bool bOn = true)
{
    static QAndroidJniObject m_wakeLock;
    QAndroidJniEnvironment env;
    QAndroidJniObject activity = androidActivity();

    if(!bOn)        //关闭
    {
        if(m_wakeLock.isValid())
        {
            m_wakeLock.callMethod<void>("release");
            CHECK_EXCEPTION();
        }
        return;
    }

    QAndroidJniObject name = QAndroidJniObject::getStaticObjectField(   //获取Context
                "android/content/Context",
                "POWER_SERVICE",
                "Ljava/lang/String;"
                );
    CHECK_EXCEPTION();

    QAndroidJniObject powerService = activity.callObjectMethod(     //调用getSystemService函数
                "getSystemService",
                "(Ljava/lang/String;)Ljava/lang/Object;",
                name.object<jstring>());
    CHECK_EXCEPTION();

    QAndroidJniObject tag = QAndroidJniObject::fromString("QtJniWakeLock");

    // 10 == SCREEN_BRIGHT_WAKE_LOCK
    //  6 == SCREEN_DIM_WAKE_LOCK
    // getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    //  before setContentView() was called.
    m_wakeLock = powerService.callObjectMethod(             //调用newWakeLock
                "newWakeLock",
                "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;",
                10,         //SCREEN_BRIGHT_WAKE_LOCK
                tag.object<jstring>()
                );
    CHECK_EXCEPTION();

    if(m_wakeLock.isValid())        //锁定
    {
        qDebug() << "屏幕常量开启中...";
        m_wakeLock.callMethod<void>("acquire");
        CHECK_EXCEPTION();
    }
    else
        qDebug() << "屏幕常量失败!";
}

QString _Platform::getSdcardPath()
{
    static QString path;
    if(path.isEmpty())
    {
        QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod(
                    MAIN_ACTIVITY_PATH
                    , "getSdcardPath"
                    , "()Ljava/lang/String;");

        path = str.toString();
        if(path.isEmpty())
        {
            QDir dir("/storage/emulated/0");
            if(dir.exists())
            {
                path = "/storage/emulated/0";
                qDebug() << "Get SDCard Path Fail,Set to Default Value:" << path;
                return path;
            }
            dir.setPath("/mnt/sdcard");
            if(dir.exists())
            {
                path = "/mnt/sdcard";
                qDebug() << "Get SDCard Path Fail,Set to Default Value:" << path;
                return path;
            }
            qDebug() << "Get SDCard Path Fail";
            return "";
        }
    }
    else
        qDebug() << "SDCard Path:" << path;

    return path;
}

QString _Platform::getExternalStorageDirectory()
{
    QAndroidJniEnvironment env;
    QAndroidJniObject externalStorageDir = QAndroidJniObject::callStaticObjectMethod(
                "android/os/Environment",
                "getExternalStorageDirectory",
                "()Ljava/io/File;"
                );
    CHECK_EXCEPTION()
    qDebug() << QString("外部存储目录:%1").arg(externalStorageDir.toString());
    return externalStorageDir.toString();
}

QString _Platform::getNetworkState()
{
    QAndroidJniEnvironment env;

    QAndroidJniObject activity = androidActivity();
    //get network state
    QAndroidJniObject connectivity = QAndroidJniObject::getStaticObjectField(
                "android/content/Context",
                "CONNECTIVITY_SERVICE",
                "Ljava/lang/String;");
    CHECK_EXCEPTION()

    if(connectivity.isValid())
    {
        qDebug() << "connectivity id - " << connectivity.toString();
        QAndroidJniObject connectivityService = activity.callObjectMethod(
                    "getSystemService",
                    "(Ljava/lang/String;)Ljava/lang/Object;",
                    connectivity.object<jstring>());
        CHECK_EXCEPTION()
        qDebug() << "got connectivity service - " << connectivityService.isValid();
        if(connectivityService.isValid())
        {
            QAndroidJniObject networkInfo = connectivityService.callObjectMethod(
                        "getActiveNetworkInfo",
                        "()Landroid/net/NetworkInfo;");
            CHECK_EXCEPTION()
                    qDebug() << "got NetworkInfo - " << networkInfo.isValid();
            if(networkInfo.isValid())
            {
                qDebug() << QString("网络状态：已连接(%1)").arg(networkInfo.toString());
                return networkInfo.toString();
            }
            else
            {
                qDebug() << QString("网络状态：未连接-3");
                return "";
            }
        }
        qDebug() << QString("网络状态：未连接-2");
        return "";
    }
    qDebug() << QString("网络状态：未连接-1");
    return "";
}

QString _Platform::getAndroidInfo(int type)
{
    QAndroidJniEnvironment env;
    QAndroidJniObject activity = androidActivity();

    QAndroidJniObject appInfo = activity.callObjectMethod(
                "getApplicationInfo",
                "()Landroid/content/pm/ApplicationInfo;");
    CHECK_EXCEPTION()

    qDebug() << "activity:" << activity.toString();
    qDebug() << "appInfo:" << appInfo.toString();

    switch(type)
    {
    case 1:
        {
            qDebug() << QString("SDK版本:%1").arg(QtAndroid::androidSdkVersion());
            return QString::number(androidSdkVersion());    //get Android SDK version
        }
        break;
    case 2:
        {
            //app's infomation
            QAndroidJniObject filesDir = activity.callObjectMethod(
                        "getFilesDir",
                        "()Ljava/io/File;");
            CHECK_EXCEPTION()
            qDebug() << QString("应用文件目录:%1").arg(filesDir.toString());
            return filesDir.toString();
        }
        break;
    case 3:
        {
            QAndroidJniObject packageName = activity.callObjectMethod<jstring>("getPackageName");
            CHECK_EXCEPTION()
            qDebug() << QString("应用包名:%1").arg(packageName.toString());
            return packageName.toString();
        }
        break;
    case 4:
        {
            QAndroidJniObject appCacheDir = activity.callObjectMethod(
                        "getCacheDir",
                        "()Ljava/io/File;");
            CHECK_EXCEPTION()
            qDebug() << QString("应用缓存目录:%1").arg(appCacheDir.toString());
            return appCacheDir.toString();
        }
        break;
    case 5:
        {
            QAndroidJniObject appClassName = appInfo.getObjectField<jstring>("className");
            CHECK_EXCEPTION()
            qDebug() << QString("应用类名:%1").arg(appClassName.toString());
            return appClassName.toString();
        }
        break;
    case 6:
        {
            QAndroidJniObject appLocation = appInfo.getObjectField(
                        "sourceDir", "Ljava/lang/String;");
            CHECK_EXCEPTION()
            qDebug() << QString("APK位置:%1").arg(appLocation.toString());
            return appLocation.toString();
        }
        break;
    }

    return "";

}



bool _Platform::checkPermission(const QString& strPermission)
{
    QtAndroid::PermissionResult r = QtAndroid::checkPermission(strPermission);
    if(r == QtAndroid::PermissionResult::Denied)
        return false;
   return true;
}

bool _Platform::requestPermission(const QString& strPermission, int timeoutMs)
{
    QtAndroid::PermissionResult r = QtAndroid::checkPermission(strPermission);
    if(r == QtAndroid::PermissionResult::Denied)
    {
        r = QtAndroid::requestPermissionsSync(QStringList() << strPermission, timeoutMs).value(strPermission, QtAndroid::PermissionResult::Denied);
        //r = QtAndroid::checkPermission(strPermission);

        if(r == QtAndroid::PermissionResult::Denied)
        {
             return false;
        }
   }
   return true;
}

void _Platform::showToast(const QString &msg)
{
    QAndroidJniEnvironment env;
    QAndroidJniObject activity = QtAndroid::androidActivity();
    QAndroidJniObject::callStaticMethod<void>(
                MAIN_ACTIVITY_PATH,
                "makeToast",
                "(Ljava/lang/String;)V",
                QAndroidJniObject::fromString(msg).object<jstring>()
                );
    CHECK_EXCEPTION()
}

void _Platform::showToast1(const QString &msg)
{
    QAndroidJniEnvironment env;
    QAndroidJniObject activity = androidActivity();

    activity.callMethod<void>(
                "QMessage",
                "(Ljava/lang/String;)V",
                QAndroidJniObject::fromString(msg).object<jstring>()
                );
    CHECK_EXCEPTION();
}

void _Platform::installApk(const QString &filePath)
{
    QAndroidJniEnvironment env;
    QAndroidJniObject jFilePath = QAndroidJniObject::fromString(filePath);
    QAndroidJniObject activity = QtAndroid::androidActivity();
    QAndroidJniObject::callStaticMethod<void>(
                MAIN_ACTIVITY_PATH,
                "installApk",
                "(Ljava/lang/String;Lcn.Leamus.MainActivity;)V",
                jFilePath.object<jstring>(),
                activity.object());
    CHECK_EXCEPTION()
}



#include <android/log.h>
void _Platform::customAndroidMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    int prio = ANDROID_LOG_VERBOSE;
    QByteArray localMsg = msg.toLocal8Bit();
    switch (type) {
    case QtDebugMsg:
        prio = ANDROID_LOG_DEBUG;
        break;
    case QtWarningMsg:
        prio = ANDROID_LOG_WARN;
        break;
    case QtCriticalMsg:
        prio = ANDROID_LOG_INFO;
        break;
    case QtFatalMsg:
        prio = ANDROID_LOG_FATAL;
        abort();
    default:
        break;
    }
    __android_log_write(prio, "Pleafles(Android):", localMsg.data());
}

/*
void setScreenKeepWake()
{
    QAndroidJniObject::callStaticMethod<void>(
                    MAIN_ACTIVITY_PATH
                    , "screen_KeepWake");
}
void setScreenReleaseWake()
{
    QAndroidJniObject::callStaticMethod<void>(
                    MAIN_ACTIVITY_PATH
                    , "screen_ReleaseWake");
}
*/





void _Platform::setAlipayInfo(QString appId,
                          QString pId,
                          QString targetId,
                          QString rsa2Private,
                          QString rsaPrivate)
{
    QtAndroid::runOnAndroidThread([=]() {
        QAndroidJniEnvironment env;
        QAndroidJniObject::callStaticMethod<void>(
                    "cn/Leamus/Alipay"
                    , "setAlipayInfo"
                    , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"
                    , QAndroidJniObject::fromString(appId).object<jstring>()
                    , QAndroidJniObject::fromString(pId).object<jstring>()
                    , QAndroidJniObject::fromString(targetId).object<jstring>()
                    , QAndroidJniObject::fromString(rsa2Private).object<jstring>()
                    , QAndroidJniObject::fromString(rsaPrivate).object<jstring>()
                    );

    });
}
void _Platform::aliPayVersion()
{
    QtAndroid::runOnAndroidThread([=]() {
        QAndroidJniEnvironment env;
        QAndroidJniObject::callStaticMethod<void>(
                    "cn/Leamus/Alipay"
                    , "showSdkVersion","()V");
    });
}

void _Platform::aliPay(float total_amount, int timeout_express, QString body)
{
    QtAndroid::runOnAndroidThread([=]() {
        QAndroidJniEnvironment env;
        QAndroidJniObject::callStaticMethod<void>(
                    "cn/Leamus/Alipay"
                    , "payV2"
                    , "(FILjava/lang/String;)V"
                    , total_amount, timeout_express, QAndroidJniObject::fromString(body).object<jstring>());

    });

}



#elif defined(Q_OS_LINUX)

//一个实例运行
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
bool _Platform::checkOnly()
{
    const char filename[]  = "/tmp/lockfile";
    int fd = open (filename, O_WRONLY | O_CREAT , 0644);
    int flock = lockf(fd, F_TLOCK, 0 );
    if (fd == -1) {
            perror("open lockfile/n");
            return false;
    }
    //给文件加锁
    if (flock == -1) {
            perror("lock file error/n");
            return false;
    }
    //程序退出后，文件自动解锁
    return true;
}



#elif defined(Q_OS_MACOS)



#elif defined(Q_OS_IOS)




#else




#endif
